<template>
  <!-- #ifndef APP-NVUE -->
  <view
    :class="['uni-col', sizeClass, pointClassList]"
    :style="{
      paddingLeft: `${Number(gutter)}rpx`,
      paddingRight: `${Number(gutter)}rpx`,
    }"
  >
    <slot></slot>
  </view>
  <!-- #endif -->
  <!-- #ifdef APP-NVUE -->
  <!-- 在nvue上，类名样式不生效，换为style -->
  <!-- 设置right正值失效，设置 left 负值 -->
  <view
    :class="['uni-col']"
    :style="{
      paddingLeft: `${Number(gutter)}rpx`,
      paddingRight: `${Number(gutter)}rpx`,
      width: `${nvueWidth}rpx`,
      position: 'relative',
      marginLeft: `${marginLeft}rpx`,
      left: `${right === 0 ? left : -right}rpx`,
    }"
  >
    <slot></slot>
  </view>
  <!-- #endif -->
</template>

<script>
/**
 * Col	布局-列
 * @description	搭配uni-row使用，构建布局。
 * @tutorial	https://ext.dcloud.net.cn/plugin?id=3958
 *
 * @property	{span} type = Number 栅格占据的列数
 * 						默认 24
 * @property	{offset} type = Number 栅格左侧的间隔格数
 * @property	{push} type = Number 栅格向右移动格数
 * @property	{pull} type = Number 栅格向左移动格数
 * @property	{xs} type = [Number, Object] <768px 响应式栅格数或者栅格属性对象
 * 						@description	Number时表示在此屏幕宽度下，栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
 * @property	{sm} type = [Number, Object] ≥768px 响应式栅格数或者栅格属性对象
 * 						@description	Number时表示在此屏幕宽度下，栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
 * @property	{md} type = [Number, Object] ≥992px 响应式栅格数或者栅格属性对象
 * 						@description	Number时表示在此屏幕宽度下，栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
 * @property	{lg} type = [Number, Object] ≥1200px 响应式栅格数或者栅格属性对象
 * 						@description	Number时表示在此屏幕宽度下，栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
 * @property	{xl} type = [Number, Object] ≥1920px 响应式栅格数或者栅格属性对象
 * 						@description	Number时表示在此屏幕宽度下，栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
 */
const ComponentClass = 'uni-col'

// -1 默认值，因为在微信小程序端只给Number会有默认值0
export default {
  name: 'uniCol',
  // #ifdef MP-WEIXIN
  options: {
    virtualHost: true, // 在微信小程序中将组件节点渲染为虚拟节点，更加接近Vue组件的表现
  },
  // #endif
  props: {
    span: {
      type: Number,
      default: 24,
    },
    offset: {
      type: Number,
      default: -1,
    },
    pull: {
      type: Number,
      default: -1,
    },
    push: {
      type: Number,
      default: -1,
    },
    xs: [Number, Object],
    sm: [Number, Object],
    md: [Number, Object],
    lg: [Number, Object],
    xl: [Number, Object],
  },
  data() {
    return {
      gutter: 0,
      sizeClass: '',
      parentWidth: 0,
      nvueWidth: 0,
      marginLeft: 0,
      right: 0,
      left: 0,
    }
  },
  created() {
    // 字节小程序中，在computed中读取$parent为undefined
    let parent = this.$parent

    while (parent && parent.$options.componentName !== 'uniRow') {
      parent = parent.$parent
    }

    this.updateGutter(parent.gutter)
    parent.$watch('gutter', (gutter) => {
      this.updateGutter(gutter)
    })

    // #ifdef APP-NVUE
    this.updateNvueWidth(parent.width)
    parent.$watch('width', (width) => {
      this.updateNvueWidth(width)
    })
    // #endif
  },
  computed: {
    sizeList() {
      let { span, offset, pull, push } = this

      return {
        span,
        offset,
        pull,
        push,
      }
    },
    // #ifndef APP-NVUE
    pointClassList() {
      let classList = []

      ;['xs', 'sm', 'md', 'lg', 'xl'].forEach((point) => {
        const props = this[point]
        if (typeof props === 'number') {
          classList.push(`${ComponentClass}-${point}-${props}`)
        } else if (typeof props === 'object' && props) {
          Object.keys(props).forEach((pointProp) => {
            classList.push(
              pointProp === 'span'
                ? `${ComponentClass}-${point}-${props[pointProp]}`
                : `${ComponentClass}-${point}-${pointProp}-${props[pointProp]}`,
            )
          })
        }
      })

      // 支付宝小程序使用 :class=[ ['a','b'] ]，渲染错误
      return classList.join(' ')
    },
    // #endif
  },
  methods: {
    updateGutter(parentGutter) {
      parentGutter = Number(parentGutter)
      if (!isNaN(parentGutter)) {
        this.gutter = parentGutter / 2
      }
    },
    // #ifdef APP-NVUE
    updateNvueWidth(width) {
      // 用于在nvue端，span，offset，pull，push的计算
      this.parentWidth = width
      ;['span', 'offset', 'pull', 'push'].forEach((size) => {
        const curSize = this[size]
        if ((curSize || curSize === 0) && curSize !== -1) {
          let RPX = (1 / 24) * curSize * width
          RPX = Number(RPX)
          switch (size) {
            case 'span':
              this.nvueWidth = RPX
              break
            case 'offset':
              this.marginLeft = RPX
              break
            case 'pull':
              this.right = RPX
              break
            case 'push':
              this.left = RPX
              break
          }
        }
      })
    },
    // #endif
  },
  watch: {
    sizeList: {
      immediate: true,
      handler(newVal) {
        // #ifndef APP-NVUE
        let classList = []
        for (let size in newVal) {
          const curSize = newVal[size]
          if ((curSize || curSize === 0) && curSize !== -1) {
            classList.push(
              size === 'span'
                ? `${ComponentClass}-${curSize}`
                : `${ComponentClass}-${size}-${curSize}`,
            )
          }
        }
        // 支付宝小程序使用 :class=[ ['a','b'] ]，渲染错误
        this.sizeClass = classList.join(' ')
        // #endif
        // #ifdef APP-NVUE
        this.updateNvueWidth(this.parentWidth)
        // #endif
      },
    },
  },
}
</script>

<style lang="scss" scoped>
/* breakpoints */
$--sm: 768px !default;
$--md: 992px !default;
$--lg: 1200px !default;
$--xl: 1920px !default;

$breakpoints: (
  'xs': (
    max-width: $--sm - 1,
  ),
  'sm': (
    min-width: $--sm,
  ),
  'md': (
    min-width: $--md,
  ),
  'lg': (
    min-width: $--lg,
  ),
  'xl': (
    min-width: $--xl,
  ),
);

$layout-namespace: '.uni-';
$col: $layout-namespace + 'col';

@function getSize($size) {
  /* TODO 1/24 * $size * 100 * 1%; 使用计算后的值，为了解决 vue3 控制台报错 */
  @return 0.04166666666 * $size * 100 * 1%;
}

@mixin res($key, $map: $breakpoints) {
  @if map-has-key($map, $key) {
    @media screen and #{inspect(map-get($map,$key))} {
      @content;
    }
  } @else {
    @warn "Undeinfed point: `#{$key}`";
  }
}

/* #ifndef APP-NVUE */
#{$col} {
  float: left;
  box-sizing: border-box;
}

#{$col}-0 {
  /* #ifdef APP-NVUE */
  width: 0;
  height: 0;
  margin-top: 0;
  margin-right: 0;
  margin-bottom: 0;
  margin-left: 0;
  /* #endif */
  /* #ifndef APP-NVUE */
  display: none;
  /* #endif */
}

@for $i from 0 through 24 {
  #{$col}-#{$i} {
    width: getSize($i);
  }

  #{$col}-offset-#{$i} {
    margin-left: getSize($i);
  }

  #{$col}-pull-#{$i} {
    position: relative;
    right: getSize($i);
  }

  #{$col}-push-#{$i} {
    position: relative;
    left: getSize($i);
  }
}

@each $point in map-keys($breakpoints) {
  @include res($point) {
    #{$col}-#{$point}-0 {
      display: none;
    }

    @for $i from 0 through 24 {
      #{$col}-#{$point}-#{$i} {
        width: getSize($i);
      }

      #{$col}-#{$point}-offset-#{$i} {
        margin-left: getSize($i);
      }

      #{$col}-#{$point}-pull-#{$i} {
        position: relative;
        right: getSize($i);
      }

      #{$col}-#{$point}-push-#{$i} {
        position: relative;
        left: getSize($i);
      }
    }
  }
}

/* #endif */
</style>
